Add code for a common string-to-coordinates parser.
authoroliskoli <oliskoli>
Fri, 13 Apr 2007 08:05:23 +0000 (08:05 +0000)
committeroliskoli <oliskoli>
Fri, 13 Apr 2007 08:05:23 +0000 (08:05 +0000)
Makefile.in
defs.h
garmin_tables.c
garmin_tables.h
util.c

index 60f5766ef94f1960beacdb3b8e9a40d0c60581a6..d08bcf527b7bafd38833edb5db898267bbda0b44 100644 (file)
@@ -411,7 +411,8 @@ garmin_fs.o: garmin_fs.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \
   jeeps/gpsmath.h jeeps/gpsmem.h jeeps/gpsrqst.h jeeps/gpsinput.h \
   jeeps/gpsproj.h garmin_tables.h
 garmin_tables.o: garmin_tables.c garmin_tables.h defs.h config.h queue.h \
-  gbtypes.h zlib/zlib.h zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h
+  gbtypes.h zlib/zlib.h zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h \
+  jeeps/gpsmath.h
 garmin_txt.o: garmin_txt.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \
   zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h csv_util.h garmin_fs.h \
   jeeps/gps.h jeeps/../defs.h jeeps/gpsport.h jeeps/gpsdevice.h \
@@ -655,7 +656,7 @@ units.o: units.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \
   zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h
 util_crc.o: util_crc.c
 util.o: util.c defs.h config.h queue.h gbtypes.h zlib/zlib.h zlib/zconf.h \
-  gbfile.h cet.h cet_util.h inifile.h
+  gbfile.h cet.h cet_util.h inifile.h jeeps/gpsmath.h
 uuid.o: uuid.c uuid.h
 vcf.o: vcf.c defs.h config.h queue.h gbtypes.h zlib/zlib.h zlib/zconf.h \
   gbfile.h cet.h cet_util.h inifile.h jeeps/gpsmath.h jeeps/gps.h \
diff --git a/defs.h b/defs.h
index 0eb901d9ebe6e5c6fb4d013a5c6384ff081cf201..5117a1183a124444e40933e709d361a2a868b3b7 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -850,6 +850,22 @@ void   le_write_double(void *p, double d);
 double ddmm2degrees(double ddmm_val);
 double degrees2ddmm(double deg_val);
 
+typedef enum {
+       grid_unknown = -1,
+       grid_lat_lon_ddd = 0,
+       grid_lat_lon_dmm = 1,
+       grid_lat_lon_dms = 2,
+       grid_bng = 3,
+       grid_utm = 4
+} grid_type;
+
+#define GRID_INDEX_MIN grid_lat_lon_ddd
+#define GRID_INDEX_MAX grid_utm
+#define DATUM_WGS84    118
+
+int parse_coordinates(const char *str, int datum, const grid_type grid,
+       double *latitude, double *longitude, const char *module);
+
 /*
  *  From util_crc.c
  */
index a82369967a76e6632b204dc3cbe613f2e5dbf213..47feca023608e1bfafdcd257bd8cb9c53213450a 100644 (file)
@@ -21,6 +21,8 @@
  */
 
 #include "garmin_tables.h"
+#include "jeeps/gpsmath.h"
+
 #include <stdio.h>
 #include <string.h>
 
@@ -597,6 +599,49 @@ char *gt_display_mode_names[] = {
        "Symbol & Description"
 };
 
+typedef struct {
+       char *shortname;
+       char *longname;
+       grid_type grid;
+} grid_mapping_t;
+
+/* gt_mps_grid_names: !!! degree sign substituted with '*' !!! */
+
+grid_mapping_t gt_mps_grid_names[] =
+{
+       { "ddd",        "Lat/Lon hddd.ddddd*",          grid_lat_lon_ddd },
+       { "dmm",        "Lat/Lon hddd*mm.mmm'",         grid_lat_lon_dmm },
+       { "dms",        "Lat/Lon hddd*mm'ss.s\"",       grid_lat_lon_dms },
+       { "bng",        "British National Grid",        grid_bng },
+       { "utm",        "UTM",                          grid_utm },
+       { NULL, NULL,   0 }
+};
+
+/* gt_mps_datum_names: */
+
+typedef struct {
+       char *jeeps_name;
+       char *mps_name;
+} datum_mapping_t;
+
+/* will be continued (when requested) */       
+datum_mapping_t gt_mps_datum_names[] = 
+{
+       { "Alaska-NAD27",       "NAD27 Alaska" },
+       { "Bahamas NAD27",      "NAD27 Bahamas" },
+       { "Canada_Mean(NAD27)", "NAD27 Canada" },
+       { "Canal_Zone_(NAD27)", "NAD27 Canal Zone" },
+       { "Carribean NAD27",    "NAD27 Caribbean" },
+       { "Cent America NAD27", "NAD27 Central" },
+       { "Cuba NAD27",         "NAD27 Cuba" },
+       { "Geodetic Datum 49",  "Geodetic Datum '49" },
+       { "Greenland NAD27",    "NAD27 Greenland" },
+       { "Mexico NAD27",       "NAD27 Mexico" },
+       { "North America 83",   "NAD83" },
+       { "OSGB36",             "Ord Srvy Grt Britn" },
+       { NULL, NULL }
+};
+
 unsigned char
 gt_switch_display_mode_value(const unsigned char display_mode, const int protoid, const char device)
 {
@@ -834,6 +879,77 @@ gt_get_icao_cc(const char *country, const char *shortname)
        return NULL;
 }
 
+grid_type
+gt_lookup_grid_type(const char *grid_name, const char *module)
+{
+       grid_mapping_t *g;
+       
+       for (g = gt_mps_grid_names; (g->shortname); g++) {
+               if ((case_ignore_strcmp(grid_name, g->shortname) == 0) ||
+                   (case_ignore_strcmp(grid_name, g->longname) == 0))
+                       return g->grid;
+       }
+       
+       fatal("%s: Unsupported grid (%s)! See GPSBabel help for supported grids.\n",
+               module, grid_name);
+
+       return grid_unknown;    /* (warnings) */
+}
+
+char *
+gt_get_mps_grid_longname(const grid_type grid, const char *module)
+{
+       if ((grid < GRID_INDEX_MIN) || (grid > GRID_INDEX_MAX))
+               fatal("%s: Grid index out of range %d (%d..%d)!",
+                       module, (int) grid,
+                       (int)GRID_INDEX_MIN, (int)GRID_INDEX_MAX);
+       return gt_mps_grid_names[grid].longname;
+}
+
+char *
+gt_get_mps_datum_name(const int datum_index)
+{
+       char *result;
+       datum_mapping_t *d;
+       
+       result = GPS_Math_Get_Datum_Name(datum_index);
+
+       for (d = gt_mps_datum_names; (d->jeeps_name); d++)
+               if (case_ignore_strcmp(result, d->jeeps_name) == 0) return d->mps_name;
+
+       return result;
+}
+
+int
+gt_lookup_datum_index(const char *datum_str, const char *module)
+{
+       datum_mapping_t *d;
+       int result;
+       const char *name = datum_str;
+       
+       for (d = gt_mps_datum_names; (d->jeeps_name); d++) {
+               if (case_ignore_strcmp(name, d->mps_name) == 0) {
+                       name = d->jeeps_name;
+                       break;
+               }
+       }
+       
+       result = GPS_Lookup_Datum_Index(name);
+       
+       if (result < 0) {
+               char *tmp;
+               xasprintf(&tmp, "%s mean", datum_str);
+               result = GPS_Lookup_Datum_Index(tmp);
+               xfree(tmp);
+       }
+
+       is_fatal(result < 0,
+               "%s: Unsupported datum (%s)! See GPSBabel help for supported datums.",
+                       module, datum_str);
+
+       return result;
+}
+
 #if MAKE_TABLE
 
 /*
index 79667843c705d6da68ce5fb103690ea3a92a41b1..c846c94c57d49ede593fb5e66b8bc81578c69c4a 100644 (file)
@@ -92,4 +92,9 @@ unsigned char gt_convert_category(const char *name, int *category);
 
 unsigned char gt_switch_display_mode_value(const unsigned char display_mode, const int protoid, const char device);
 
+grid_type gt_lookup_grid_type(const char *grid_name, const char *module);
+char *gt_get_mps_grid_longname(const grid_type grid, const char *module);
+int gt_lookup_datum_index(const char *datum_str, const char *module);
+char *gt_get_mps_datum_name(const int datum_index);
+
 #endif
diff --git a/util.c b/util.c
index 1af7d25e629c4d83ad9b1a0de8cdbab63e228adf..617199e7d67c30890dfd9386aee2c4f2bcba1ab1 100644 (file)
--- a/util.c
+++ b/util.c
@@ -20,6 +20,8 @@
  */
 
 #include "defs.h"
+#include "jeeps/gpsmath.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
@@ -992,6 +994,117 @@ double degrees2ddmm(double deg_val) {
        return (double) (deg * 100.0) + ((deg_val - deg) * 60.0);
 }
 
+/* 
+ * Convert string 'str' into geodetic latitide & longitude values. The format
+ * will be interpreted depending on 'grid' parameter.
+ *
+ * return value: number of characters efective parsed
+ */
+
+int
+parse_coordinates(const char *str, int datum, const grid_type grid, 
+       double *latitude, double *longitude, const char *module)
+{
+       double lat, lon;
+       unsigned char lathemi, lonhemi;
+       int deg_lat, deg_lon, min_lat, min_lon;
+       char map[3];
+       int utmz, utme, utmn;
+       char utmc;
+       int valid, result, ct;
+       double lx, ly;
+       const char *format;
+       
+       valid = 1;
+       
+       switch(grid) {
+
+               case grid_lat_lon_ddd:
+                       format = "%c%lf %c%lf%n";
+                       ct = sscanf(str, format,
+                               &lathemi, &lat, &lonhemi, &lon, &result);
+                       valid = (ct == 4);
+                       break;
+
+               case grid_lat_lon_dmm:
+                       format = "%c%d %lf %c%d %lf%n";
+                       ct = sscanf(str, format,
+                               &lathemi, &deg_lat, &lat, &lonhemi, &deg_lon, &lon, &result);
+                       valid = (ct == 6);
+                       if (valid) {
+                               lat = (double)deg_lat + (lat / (double)60);
+                               lon = (double)deg_lon + (lon / (double)60);
+                       }
+                       break;
+               
+               case grid_lat_lon_dms:
+                       format = "%c%d %d %lf %c%d %d %lf%n";
+                       ct = sscanf(str, format,
+                               &lathemi, &deg_lat, &min_lat, &lat, &lonhemi, &deg_lon, &min_lon, &lon,
+                               &result);
+                       valid = (ct == 8);
+                       if (valid) {
+                               lat = (double)deg_lat + ((double)min_lat / (double)60) + (lat / (double)3600.0);
+                               lon = (double)deg_lon + ((double)min_lon / (double)60) + (lon / (double)3600.0);
+                       }
+                       break;
+               
+               case grid_bng:
+                       format = "%2s %lf %lf%n";
+                       ct = sscanf(str, format,
+                               map, &lx, &ly,
+                               &result);
+                       valid = (ct == 3);
+                       if (valid) {
+                               if (! GPS_Math_UKOSMap_To_WGS84_M(map, lx, ly, &lat, &lon))
+                                       fatal("%s: Unable to convert BNG coordinates (%s)!\n",
+                                               module, str);
+                       }
+                       datum = DATUM_WGS84;    /* fix */
+                       lathemi = lonhemi = '\0';
+                       break;
+                       
+               case grid_utm:
+                       format = "%d %c %d %d%n";
+                       ct = sscanf(str, format,
+                               &utmz, &utmc, &utme, &utmn,
+                               &result);
+                       valid = (ct == 4);
+                       if (valid) {
+                               valid = GPS_Math_UTM_EN_To_Known_Datum(&lat, &lon, utme, utmn, utmz, utmc, datum);
+                               if (! valid)
+                                       fatal("%s: Unable to convert UTM coordinates (%s)!\n",
+                                               module, str);
+                       }
+                       lathemi = lonhemi = '\0';
+                       break;
+                       
+               default:
+                       /* this should never happen in a release version */
+                       fatal("%s/util: Unknown grid in parse_coordinates (%d)!\n",
+                               module, (int)grid);
+       }
+       
+       if (!valid) {
+               warning("%s: sscanf error using format \"%s\"\n", module, format);
+               fatal(  "%s: could not convert data \"%s\"!\n", module, str);
+       }
+       
+       if (lathemi == 'S') lat = -lat;
+       if (lonhemi == 'W') lon = -lon;
+
+       if (datum != DATUM_WGS84) {
+               double alt;
+               GPS_Math_Known_Datum_To_WGS84_M(lat, lon, (double) 0.0,
+                       &lat, &lon, &alt, datum);
+       }
+
+       if (latitude) *latitude = lat;
+       if (longitude) *longitude = lon;
+               
+       return result;
+}
+
 /*
  * replace a single occurrence of "search" in  "s" with "replace".
  * Returns an allocated copy if substitution was made, otherwise returns NULL.